<?php

/**
 * URL请求解析类
 * 
 * @author keluo<pycorvn@yeah.net>
 * @since 2015-01-24
 */
class SCRequest {
    
    public $controller; // 当前请求的控制器名
    public $action; // 当前请求的方法名
    public $baseURI; // 当前请求基本url
    public $requestURI; // 当前请求的url
    
    private $_get = array();
    private $_post = array();
    private $_param = array();
    private $_segment = array();
    
    private static $_instance;
    
    private function __construct() {
        $this->parseGet();
        $this->parsePost();
        $this->parseParam();
        $this->parseSegment();
    }
    
    public function __set($name, $value) {
        throw new Exception('被禁止的操作：'.$name.' = '.$value);
    }
    
    public function __clone() {}
    
    public static function instance() {
        if(!(self::$_instance instanceof self)) {
            self::$_instance = new self();
        }
        return self::$_instance;
    }
    
    /**
     * 
     * 获取/设置当前GET请求中指定参数值
     */
    public function get() {
        $argNum = func_num_args();
        if(0 == $argNum) {
            return $this->_get;
        }
        if(1 == $argNum) {
            if(empty($this->_get)) {
                return false;
            }
            if(false === array_key_exists(strtolower(func_get_arg(0)), $this->_get)) {
                return false;
            }
            return $this->_get[strtolower(func_get_arg(0))];
        }
        
        if(2 == $argNum) {
            $this->_get[func_get_arg(0)] = func_get_arg(1);
        }
    }
    
    /**
     * 获取/设置当前POST请求中指定参数值
     * @example
     *  SCS::request()->post('a'); // 获取参数a的值
     *  SCS::request()->post('a', 1); // 设置参数a的值为1
     */
    public function post() {
        $args = func_get_args();
        if(empty($args)) return $this->_post;
        if(count($args) == 1) { // 取值
        	if(isset($this->_post[$args[0]])) {
        		return is_array($this->_post[$args[0]]) ? $this->_post[$args[0]] : trim($this->_post[$args[0]]);
        	} else {
        		return false;
        	}
        } elseif(count($args) == 2) { // 设置值
            $this->_post[$args[0]] = $args[1];
        }
    }
    
    /**
     * 获取/设置当前REQUEST请求中指定参数值
     * @example
     *  SCS::request()->param('a'); // 获取参数a的值
     *  SCS::request()->param('a', 1); // 设置参数a的值为1
     */
    public function param() {
        $args = func_get_args();
        if(empty($args)) return $this->_param;
        if(count($args) == 1) { // 取值
            return isset($this->_param[$args[0]]) ? trim($this->_param[$args[0]]) : false;
        } elseif(count($args) == 2) { // 设置值
            $this->_param[$args[0]] = $args[1];
        }
    }
    
    /**
     * 获取/设置当前REQUEST请求中指定段
     * @param integer $index url请求分段索引，0为控制器名；1为动作名
     * @example
     *  对于url： http://domain.com/?blog/view/1，1表示blog的id，获取id的方式：
     *  SCS::request()->segment(2);
     */
    public function segment($index) {
        return isset($this->_segment[$index]) ? trim($this->_segment[$index]) : false;
    }
    
    /**
     * 路由重定向
     * @param string $route 路由地址
     * @param array $params 参数
     * @param boolean $exit 是否立即终止程序执行
     * @example
     * SCS::request()->route('index/test', array('id' => 1, 'name' => 'keluo'));
     */
    public function route($route='', $params = array(), $exit = true) {
        $this->redirect(SCS::url()->create($route, $params), $exit);
    }
    
    /**
     * url重定向
     * @param string $url 完整url地址
     * @param boolean $exit 是否立即终止程序执行
     */
    public function redirect($url, $exit = true) {
        header('Location: '.$url);
        $exit && exit;
    }
    
    /**
     *
     * 检查当前请求是否为post方式
     * @param boolean $check_token 是否检查token
     */
    public function isPost($check_token = false) {
        
        // @todo 检查表单token ...
        
        return 0 == strcasecmp($_SERVER['REQUEST_METHOD'], 'POST');
    }
    
    private function parseBaseURI() {
        $self = strtolower(trim($_SERVER['SCRIPT_NAME'], '/'));
        $baseURI = substr($self, 0, strpos($self, 'index.php'));
        $this->baseURI = $baseURI ? '/'.trim($baseURI, '/') : '';
    }
    
    private function parseRequestURI() {
        $requestURI = $_SERVER['REQUEST_URI'];
        $requestURI = preg_replace('/\?.*/', '', $requestURI);
        $requestURI = preg_replace('/'.str_replace('/', '\/', $this->baseURI).'/i', '', $requestURI, 1);
        $requestURI = str_replace('index.php', '', $requestURI);
        $this->requestURI = ltrim(trim($requestURI, '/'), '?');
    }
    
    /**
     * 
     * 解析GET请求
     */
    private function parseGet() {
        $this->parseBaseURI();
        $this->parseRequestURI();
        if(strlen($this->requestURI)) {
            $splits = explode('/', $this->requestURI);
            $this->controller = $splits[0];
            if(!isset($splits[1])) {
                $this->action = 'index';
            } else {
                $this->action = $splits[1];
                array_shift($splits);
                array_shift($splits);
                if(!empty($splits)) {
                    if(count($splits) % 2 != 0) {
                        array_pop($splits);
                    }
                    
                    $keys = $values = array();
                    for($idx = 0; $idx < count($splits); $idx++) {
                        if($idx % 2 == 0) {
                            $keys[] = $splits[$idx];
                        } else {
                            $values[] = urldecode($splits[$idx]);
                        }
                    }
                    if(!empty($keys) && !empty($values)) {
                        $this->_get = array_combine($keys, $values);
                    }
                }
            }
        } else {
            $this->controller = 'index';
            $this->action = 'index';
        }
    }
    
    /**
     * 
     * 解析POST请求
     */
    private function parsePost() {
        $this->_post = $_POST;
        //self::$_post = array_map('trim', $_POST); // 预处理post变量会引起其他问题，比如通过二进制文件流，所以此处已不作处理
    }
    
    /**
     *
     * 解析REQUEST请求
     */
    private function parseParam() {
        $this->_param = array_merge($this->_get, $this->_post);
    }
    
    /**
     * 解析url请求段
     * @return array
     */
    private function parseSegment() {
        $segments = explode('/', $this->requestURI);
        foreach($segments as $k=>$segment) {
            if(strlen(trim($segment, '/'))) {
                $this->_segment[] = $segment;
            }
        }
    }
}